package com.avic.map.common.scheduled;


import com.alibaba.fastjson.JSONObject;
import com.avic.map.common.constant.CacheConstant;
import com.avic.map.common.constant.LocalResourceConstant;
import com.avic.map.common.model.MapCommonModel;
import com.avic.map.common.model.ShipStaticInfoModel;
import com.avic.map.common.model.SocketCommonModel;
import com.avic.map.common.model.enums.MapDataStatusEnums;
import com.avic.map.common.model.enums.SocketDataTypeEnums;
import com.avic.map.service.CarResourceService;
import com.avic.map.service.MapShipResourceService;
import com.avic.map.service.ShipResourceService;
import com.avic.map.service.SingleSoldierResourceService;
import com.avic.map.websocket.MapSocketHandler;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description 定时任务、整理地图应急数据：本地缓存数据、redis数据、数据库持久数据
 * @Author huangsheng
 * @Date 2018/9/29 20:20
 */
@Component
@Slf4j
public class MapServiceScheduled {

    /**
     * redis对象
     */
    @Resource(name = CacheConstant.REDIS_BEAN_NAME)
    private RedisTemplate redisTemplate;

    /**
     * 地图数据接口
     */
    @Autowired
    private MapShipResourceService mapShipResourceService;

    @Autowired
    private ShipResourceService shipResourceService;

    /**
     * 地图数据接口
     */
    @Autowired
    private CarResourceService carResourceService;

    /**
     * 地图数据接口
     */
    @Autowired
    private SingleSoldierResourceService singleSoldierResourceService;

    /**
     * json框架
     */
    @Autowired
    private ObjectMapper objectMapper;

    /**
     * socket 操作类
     * 用户发送消息。接收用户消息并处理
     */
    @Autowired
    private MapSocketHandler mapSocketHandler;

    /**
     * 离线时间5分钟
     */
    public static final long OFFLINE_TIME = 300000;

    /**
     * 失效时间1个小时
     */
    public static final long CAR_INVALID_TIME = 3600000;

    /**
     * VDM失效时间半个小时
     */
    public static final long VDM_SHIP_INVALID_TIME = 1800000;

    /**
     * VDO失效时间1个小时
     */
    public static final long VDO_SHIP_INVALID_TIME = 3600000;

    /**
     * 单兵失效时间1个小时
     */
    public static final long SOLDIER_INVALID_TIME = 3600000;

    /**
     * 整理redis船 VIDO数据舶离线、失效数据
     * 创建传输任务, 第一次延时2分钟, 6分钟描一次
     * <p>
     * 1.整理本地Map变量数据
     * 2.整理redis数据
     * 3.同步实例化数据数据
     */
    @Scheduled(initialDelay = 1000 * 60 * 2, fixedRate = 1000 * 60 * 3)
    public void clearRedisInvalidShipData() {
        Map<Long, MapCommonModel> shipLastPositionMap = new HashMap<>(LocalResourceConstant.SHIP_CURRENT_POSITION_MAP.size());
        shipLastPositionMap.putAll(LocalResourceConstant.SHIP_CURRENT_POSITION_MAP);

        shipLastPositionMap.forEach((shipMssi, shipPositionModel) -> {
            try {
                log.info("清理船舶数据 {}", objectMapper.writeValueAsString(shipPositionModel));
            } catch (JsonProcessingException e) {
            }

            long timeDifference = System.currentTimeMillis() - shipPositionModel.getDataTime();
            if (shipPositionModel.getStatus() == MapDataStatusEnums.VIDM.getType()) {
                if (timeDifference >= VDM_SHIP_INVALID_TIME) {
                    log.info("移除VOM船舶 {} 失效数据", shipMssi);
                    log.info("移除船舶 {} 失效数据", shipMssi);
                    LocalResourceConstant.SHIP_CURRENT_POSITION_MAP.remove(shipMssi);
                    // 删除静体名称数据
                    LocalResourceConstant.VDM_SHIP_STATE_DB_MAP.remove(String.valueOf(shipMssi));
                    // 删除持久化数据
                    mapShipResourceService.deleteMapShipResource(String.valueOf(shipMssi));
                    // 删除redis数据
                    redisTemplate.opsForHash().delete(CacheConstant.REDIS_MAP_CURRENT_SHIP_SPACE, String.valueOf(shipMssi));
                    // 删除redis坐标数据
//                    redisTemplate.delete(CacheConstant.REDIS_SHIP_POSITION_HISTORY_SPACE + shipMssi);
                    //广播消息
                    shipPositionModel.setRemove(true);
                    mapSocketHandler.sendMessageToAllUsers(new TextMessage(
                            JSONObject.toJSONString(new SocketCommonModel<>(SocketDataTypeEnums.OBJECT_MAP_COMMON_MODEL, shipPositionModel))));
                }
            } else {
                if (timeDifference >= VDO_SHIP_INVALID_TIME) {
                    log.info("移除VDO船舶 {} 失效数据", shipMssi);
                    LocalResourceConstant.SHIP_CURRENT_POSITION_MAP.remove(shipMssi);
                    // 删除持久化数据
                    shipResourceService.updateShipState(MapDataStatusEnums.INVALID.getType(), String.valueOf(shipMssi));
                    // 删除redis数据
                    redisTemplate.opsForHash().delete(CacheConstant.REDIS_MAP_CURRENT_SHIP_SPACE, String.valueOf(shipMssi));
                    // 删除redis坐标数据
//                    redisTemplate.delete(CacheConstant.REDIS_SHIP_POSITION_HISTORY_SPACE + shipMssi);
                    //广播消息
                    shipPositionModel.setRemove(true);
                    mapSocketHandler.sendMessageToAllUsers(new TextMessage(
                            JSONObject.toJSONString(new SocketCommonModel<>(SocketDataTypeEnums.OBJECT_MAP_COMMON_MODEL, shipPositionModel))));
                }
            }
        });
    }

    /**
     * 清理redis失效数据
     * 创建传输任务, 第一次延时5分钟, 5分钟扫描一次
     */
    @Scheduled(initialDelay = 1000 * 60 * 3, fixedRate = 1000 * 60 * 4)
    public void clearRedisInvalidCarData() {
        Map<String, MapCommonModel> carLastPositionMap = new HashMap<>(LocalResourceConstant.CAR_CURRENT_POSITION_MAP.size());
        carLastPositionMap.putAll(LocalResourceConstant.CAR_CURRENT_POSITION_MAP);
        carLastPositionMap.forEach((carNumber, mapCommonModel) -> {
            try {
                log.info("清理车辆数据 {}", objectMapper.writeValueAsString(mapCommonModel));
            } catch (JsonProcessingException e) {
            }
            long timeDifference = System.currentTimeMillis() - mapCommonModel.getDataTime();
            // 如果状态已经是离线，时间超过半个小时，删除历史轨迹
            if (mapCommonModel.getStatus() == MapDataStatusEnums.CAR_OFFLINE.getType()) {
                // 船舶数据失效 30分钟,移除缓存数据
                if (timeDifference >= CAR_INVALID_TIME) {
                    log.info("移除车辆 {} 失效数据", carNumber);
                    LocalResourceConstant.CAR_CURRENT_POSITION_MAP.remove(carNumber);
                    LocalResourceConstant.CAR_CURRENT_STATE_MAP.remove(carNumber);
                    // 删除持久化数据
                    carResourceService.updateCarState(MapDataStatusEnums.INVALID.getType(), carNumber);
                    // 删除redis数据
                    redisTemplate.opsForHash().delete(CacheConstant.REDIS_MAP_CURRENT_CAR_SPACE, carNumber);
                    // 删除redis坐标数据
//                    redisTemplate.delete(CacheConstant.REDIS_CAR_POSITION_HISTORY_SPACE + carNumber);

                    mapCommonModel.setRemove(true);
                    //广播消息
                    mapSocketHandler.sendMessageToAllUsers(new TextMessage(
                            JSONObject.toJSONString(new SocketCommonModel<>(SocketDataTypeEnums.OBJECT_MAP_COMMON_MODEL, mapCommonModel))));
                }
            } else {
                //船舶离线
                if (timeDifference >= OFFLINE_TIME) {
                    MapCommonModel mapShipData = LocalResourceConstant.CAR_CURRENT_POSITION_MAP.get(carNumber);
                    if (mapCommonModel.getStatus() == MapDataStatusEnums.CAR_ONLINE.getType()) {
                        mapShipData.setStatus(MapDataStatusEnums.CAR_OFFLINE.getType());
                        LocalResourceConstant.CAR_CURRENT_POSITION_MAP.put(carNumber, mapShipData);
                        LocalResourceConstant.CAR_CURRENT_STATE_MAP.put(carNumber, MapDataStatusEnums.CAR_OFFLINE.getType());
                        // 数据正常有效，修改状态
                        carResourceService.updateCarState(MapDataStatusEnums.CAR_OFFLINE.getType(), carNumber);
                    } else if (mapCommonModel.getStatus() == MapDataStatusEnums.CAR_ONLINE_EMERGENCY.getType()) {
                        mapShipData.setStatus(MapDataStatusEnums.CAR_OFFLINE_EMERGENCY.getType());
                        LocalResourceConstant.CAR_CURRENT_POSITION_MAP.put(carNumber, mapShipData);
                        LocalResourceConstant.CAR_CURRENT_STATE_MAP.put(carNumber, MapDataStatusEnums.CAR_OFFLINE_EMERGENCY.getType());
                        // 数据正常有效，修改状态
                        carResourceService.updateCarState(MapDataStatusEnums.CAR_OFFLINE_EMERGENCY.getType(), carNumber);
                    }
                    // 更新redis数据状态
                    try {
                        redisTemplate.opsForHash().put(CacheConstant.REDIS_MAP_CURRENT_CAR_SPACE, carNumber, objectMapper.writeValueAsString(mapShipData));
                    } catch (Exception e) {
                        log.warn("清理车辆数据时，redis发生错误，{}", e.getMessage());
                    }
                    //广播消息
                    mapSocketHandler.sendMessageToAllUsers(new TextMessage(
                            JSONObject.toJSONString(new SocketCommonModel<>(SocketDataTypeEnums.OBJECT_MAP_COMMON_MODEL, mapShipData))));
                }
            }
        });
    }

    /**
     * 清理redis失效的单兵数据
     * <p>
     * 创建传输任务, 第一次延时4分钟, 5分钟扫描一次
     */
    @Scheduled(initialDelay = 1000 * 60 * 4, fixedRate = 1000 * 60 * 5)
    public void clearRedisInvalidSoldierData() {
        Map<String, MapCommonModel> soldierLastPositionMap = new HashMap<>(LocalResourceConstant.SOLDIER_CURRENT_POSITION_MAP.size());
        soldierLastPositionMap.putAll(LocalResourceConstant.SOLDIER_CURRENT_POSITION_MAP);
        soldierLastPositionMap.forEach((soldierNumber, soldierMapCommonModel) -> {
            try {
                log.info("清理单兵数据 {}", objectMapper.writeValueAsString(soldierMapCommonModel));
            } catch (JsonProcessingException e) {
            }
            long timeDifference = System.currentTimeMillis() - soldierMapCommonModel.getDataTime();
            // 如果状态已经是离线，时间超过半个小时，删除历史轨迹
            if (soldierMapCommonModel.getStatus() == MapDataStatusEnums.WALKIE_TALKIE_SOLDIER_OFFLINE.getType() ||
                    soldierMapCommonModel.getStatus() == MapDataStatusEnums.G_TALKIE_SOLDIER_OFFLINE.getType()) {
                // 单兵数据失效 一个小时分钟,移除缓存数据
                if (timeDifference >= SOLDIER_INVALID_TIME) {
                    log.info("移除单兵 {} 失效数据", soldierNumber);
                    LocalResourceConstant.SOLDIER_CURRENT_POSITION_MAP.remove(soldierNumber);
                    LocalResourceConstant.SOLDIER_CURRENT_STATE_MAP.remove(soldierNumber);
                    // 删除持久化数据
                    singleSoldierResourceService.updateSoldierState(soldierNumber, MapDataStatusEnums.INVALID.getType());
                    // 删除redis数据
                    redisTemplate.opsForHash().delete(CacheConstant.REDIS_MAP_CURRENT_SOLDIER_SPACE, soldierNumber);
                    // 删除redis坐标数据
//                    redisTemplate.delete(CacheConstant.REDIS_SOLDIER_POSITION_HISTORY_SPACE + soldierNumber);

                    //广播消息
                    soldierMapCommonModel.setRemove(true);
                    mapSocketHandler.sendMessageToAllUsers(new TextMessage(
                            JSONObject.toJSONString(new SocketCommonModel<>(SocketDataTypeEnums.OBJECT_MAP_COMMON_MODEL, soldierMapCommonModel))));
                }
            } else {
                //单兵离线
                if (timeDifference >= OFFLINE_TIME) {
                    MapCommonModel mapSoldierData = LocalResourceConstant.SOLDIER_CURRENT_POSITION_MAP.get(soldierNumber);
                    int offlineState = MapDataStatusEnums.WALKIE_TALKIE_SOLDIER_OFFLINE.getType();
                    if (soldierMapCommonModel.getStatus() == MapDataStatusEnums.G_TALKIE_SOLDIER_ONLINE.getType()) {

                        offlineState = MapDataStatusEnums.G_TALKIE_SOLDIER_OFFLINE.getType();
                    } else if (soldierMapCommonModel.getStatus() == MapDataStatusEnums.WALKIE_TALKIE_SOLDIER_ONLINE_EMERGENCY.getType()) {

                        offlineState = MapDataStatusEnums.WALKIE_TALKIE_SOLDIER_OFFLINE_EMERGENCY.getType();
                    } else if (soldierMapCommonModel.getStatus() == MapDataStatusEnums.G_SOLDIER_ONLINE_EMERGENCY.getType()) {

                        offlineState = MapDataStatusEnums.G_SOLDIER_OFFLINE_EMERGENCY.getType();
                    }
                    mapSoldierData.setStatus(offlineState);
                    LocalResourceConstant.SOLDIER_CURRENT_POSITION_MAP.put(soldierNumber, mapSoldierData);
                    LocalResourceConstant.SOLDIER_CURRENT_STATE_MAP.put(soldierNumber, offlineState);
                    // 数据正常有效，修改状态
                    singleSoldierResourceService.updateSoldierState(soldierNumber, offlineState);
                    // 更新redis数据状态
                    try {
                        redisTemplate.opsForHash().put(CacheConstant.REDIS_MAP_CURRENT_SOLDIER_SPACE, soldierNumber, objectMapper.writeValueAsString(mapSoldierData));
                    } catch (Exception e) {
                        log.warn("清理单兵数据时，redis发生错误，{}", e.getMessage());
                    }
                    //广播消息
                    mapSocketHandler.sendMessageToAllUsers(new TextMessage(
                            JSONObject.toJSONString(new SocketCommonModel<>(SocketDataTypeEnums.OBJECT_MAP_COMMON_MODEL, mapSoldierData))));
                }
            }
        });
    }


//    /**
//     * 凌晨2点清除轨迹点缓存
//     */
//    @Scheduled(cron = "00 00 02 * * ?")
//    public void pushMemberData() {
//        log.info("开始清理轨迹任务；时间 {}", System.currentTimeMillis());
//        redisTemplate.delete(redisTemplate.keys(CacheConstant.REDIS_SHIP_POSITION_HISTORY_SPACE + "*"));
//        redisTemplate.delete(redisTemplate.keys(CacheConstant.REDIS_CAR_POSITION_HISTORY_SPACE + "*"));
//        redisTemplate.delete(redisTemplate.keys(CacheConstant.REDIS_SOLDIER_POSITION_HISTORY_SPACE + "*"));
//
//    }
}
